package com.yyfax.pay.order.controller;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import com.yyfax.pay.common.exception.PayException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;

import com.yyfax.framework.exception.YYException;
import com.yyfax.framework.exception.YYRuntimeException;
import com.yyfax.framework.model.ExceptionContent;
import com.yyfax.framework.model.YYFaxRsp;
import com.yyfax.framework.yyfax.enums.RspCodeEnum;
import com.yyfax.pay.common.enums.PayRspCodeEnum;
import com.yyfax.pay.common.exception.YYPayException;

/**
 * API控制层统一异常处理
 * 
 * @author yuch
 * @date 2016-09-28 15:43:58
 * @since v1.0.0
 */
@RestController
@ControllerAdvice("com.yyfax.pay.order.controller.api")
public class ApiExceptionHandler {
	protected Logger logger = LoggerFactory.getLogger(getClass());

	@ExceptionHandler({ YYRuntimeException.class })
	public YYFaxRsp<ExceptionContent> handleYYRuntimeException(HttpServletRequest request, YYRuntimeException e)
			throws IOException {
		// content组装
		ExceptionContent content = new ExceptionContent(request.getRequestURL().toString());
		// rsp组装
		YYFaxRsp<ExceptionContent> base = new YYFaxRsp<ExceptionContent>();
		base.setCode(e.getCode());
		base.setMessage(e.getMessage());
		base.setContent(content);
		RspCodeEnum code = RspCodeEnum.fromValue(e.getCode());
		if (code != null) {
			base.setDisplay(code.getDisplay());
		}
		if (logger.isInfoEnabled()) {
			logger.warn("Exception: {}, {}, {}", base.getCode(), base.getMessage(), base.getDisplay(), e);
		} else {
			logger.warn("Exception: {}, {}, {}", base.getCode(), base.getMessage(), base.getDisplay());
		}
		return base;
	}

	@ExceptionHandler({ YYException.class })
	public YYFaxRsp<ExceptionContent> handleYYException(HttpServletRequest request, YYException e) throws IOException {

		logger.warn("HttpRequest error:{}", request.getRequestURL());
		logger.warn("HttpRequest error stack :", e);

		return transformException(request, e.getCode(), e.getDisplay(), e.getMessage());
	}

	@ExceptionHandler({ YYPayException.class })
	public YYFaxRsp<ExceptionContent> handleYYException(HttpServletRequest request, YYPayException e)
			throws IOException {
		logger.warn("HttpRequest error:{}", request.getRequestURL());
		logger.warn("HttpRequest error stack :", e);

		return transformException(request, e.getCode(), e.getDisplay(), e.getMessage());
	}

	// @ExceptionHandler({ ServletException.class })
	// public ServletException http404(HttpServletRequest request,
	// ServletException e) throws IOException {
	// logger.error("HttpRequest error:{}", request.getRequestURL());
	// logger.error("HttpRequest error stack :", e);
	// return e;
	// }

	@ExceptionHandler(MethodArgumentNotValidException.class)
	public YYFaxRsp<ExceptionContent> handleMethodArgumentNotValidException(HttpServletRequest request,
			MethodArgumentNotValidException e) throws IOException {
		StringBuilder sb = new StringBuilder();
		MethodArgumentNotValidException me = (MethodArgumentNotValidException) e;
		BindingResult bindingResult = me.getBindingResult();
		String display = "";
		for (FieldError fieldError : bindingResult.getFieldErrors()) {
			sb.append(fieldError.getDefaultMessage());
			display = fieldError.getDefaultMessage();
		}

		logger.error("MethodArgumentNotValidException :{}", sb);

		return transformException(request, PayRspCodeEnum.COMMON_ERROR_PARAMETER_INVALID.getValue(), display, null);
	}

	// @ExceptionHandler(RuntimeException.class)
	// public RuntimeException handleBizException(HttpServletRequest request,
	// RuntimeException e) throws IOException {
	// logger.error("runtime error occurs during :{}", request.getRequestURI());
	// logger.error("runtime error stack :", e);
	// return e;
	// }

	@ExceptionHandler({ Error.class, Exception.class, Throwable.class })
	public YYFaxRsp<ExceptionContent> exception(HttpServletRequest request, Throwable e) throws IOException {
		logger.error("Unknown error occurs during :{}", request.getRequestURI());
		logger.error("Unknown system error stack:", e);

		return transformException(request, PayRspCodeEnum.COMMON_ERR0R_NET_ERROR.getValue(), null, e.getMessage());
	}

	@ExceptionHandler({PayException.class})
	public YYFaxRsp<ExceptionContent> handlePayException(HttpServletRequest request, Throwable e) throws IOException {
		logger.error("Unknown error occurs during :{}", request.getRequestURI());
		logger.error("Unknown system error stack:", e);

		return transformException(request,((PayException)e).getCode() , ((PayException)e).getMessage(), e.getMessage());
	}

	private YYFaxRsp<ExceptionContent> transformException(HttpServletRequest request, int code, String display,
			String message) {
		ExceptionContent content = new ExceptionContent(request.getRequestURL().toString());
		// rsp组装
		YYFaxRsp<ExceptionContent> rsp = new YYFaxRsp<ExceptionContent>();

		rsp.setCode(code);
		// 统一异常处理，不展示详细异常信息
		// rsp.setMessage(message);

		rsp.setContent(content);
		if (StringUtils.isNotBlank(display)) {
			rsp.setDisplay(display);
		} else {
			RspCodeEnum rspCode = RspCodeEnum.fromValue(code);
			if (rspCode != null) {
				rsp.setDisplay(rspCode.getDisplay());
			}
		}
		rsp.setMessage(message);

		return rsp;
	}
}
